package sf.database.dao;

import sf.database.connection.WrapConnection;
import sf.database.datasource.SimpleRoutingDataSource;
import sf.database.datasource.WrapDataSource;
import sf.database.dialect.DBDialect;
import sf.database.jdbc.sql.Crud;
import sf.database.transaction.DefaultTransactionManager;
import sf.database.util.DBUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public abstract class DaoSupport {
    protected Crud crud = Crud.getInstance();


    // 当前线程(事务)
    protected SimpleRoutingDataSource dataSource;

    public DaoSupport(SimpleRoutingDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public DaoSupport() {

    }

    /**
     * 启动一个事务(默认支持子事务)
     */
    public void start() {
        DefaultTransactionManager.start();
    }

    /**
     * 获取一个当前线程的连接(事务中)，如果没有，则新建一个。
     */
    protected Connection getConnection(DataSource ds) {
        Boolean tx = DefaultTransactionManager.inTrans();
        Connection conn = null;
        try {
            if (!tx) {
                conn = dataSource.getConnection();
            } else {
                conn = DefaultTransactionManager.getCurrentThreadConnection(dataSource);
            }
            if (ds instanceof WrapDataSource && conn != null) {
                DBDialect dialect = ((WrapDataSource) ds).getDialect();
                return new WrapConnection(conn, dialect);
            }
            return conn;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从clz中获取数据源
     * @param readonly 是否只读
     * @return
     */
    protected DataSource getDataSource(boolean readonly) {
        if (dataSource.getSlaves().isEmpty()) {
            return dataSource.getMasterDataSource();
        }
        if (readonly) {
            return dataSource.getSlavesDataSources();
        } else {
            return dataSource.getMasterDataSource();
        }
    }

    /**
     * 释放一个连接，如果 Connection 不在事务中，则关闭它，否则不处理。
     */
    protected void closeConnection(Connection conn, DataSource ds) {
        Boolean tx = DefaultTransactionManager.inTrans();
        if (!tx) {
            // not in transaction
            DBUtils.closeQuietly(conn);
        }
    }

    public DBDialect getDialect(DataSource ds) {
        DBDialect dialect = DBUtils.doGetDialect(getConnection(ds), true);
        return dialect;
    }

    public void setDataSource(SimpleRoutingDataSource dataSource) {
        this.dataSource = dataSource;
    }
}
